/*!
\copyright  Copyright (c) 2022 - 2023 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file       
\ingroup    hci_tap
\brief      This is the interface to HCI TAP Stream that logs the BT HCI Interface
            traffic out off the chip for debugging purpose.

           !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
           WARNING: calling HciTapStream_ConnectToCDCDevice or
           hciTapStream_ConfigureUart functions in the code by default is a
           security risk as the HCI Interface provides the LINK Keys.

           Therefore it MUST NEVER be called in the code by DEFAULT in a
           final product.
           !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        Example of call in pydbg
           QCC5171-AA_DEV-BRD-R3-AA_LEA workspace
           ======================================
          Case 1: Redirection from HCI TAP Stream to USB CDC Virtual UART Port
            With INCLUDE_USB_DEVICE
            >>>
            apps1.fw.call.HciTapStream_ConnectToCDCDevice()
@{
*/
#include <hci_tap.h>
#include <hci_tap_private.h>
#include <panic.h>
#include <usb_app_cdc.h>
#include <usb_cdc.h>
#include <logging.h>
#include <transform.h>

#if defined(ENABLE_HCI_TAP_STREAM)
#ifdef GC_SECTIONS
/* Move all functions in KEEP_PM section to ensure they are not removed during
 * garbage collection */
#pragma unitcodesection KEEP_PM
#endif

extern HciTapPrivate hciTapPrivateData;

static bool hciTapStream_ConnectToCDCDeviceComplete(void)
{
    Source src = StreamHciTapSource(); /* should be first */
    Sink sink = UsbCdc_StreamEpSink();
    bool retVal = hciTapStream_ConnectStream(src, sink);
    if (retVal)
    {
        DEBUG_LOG_INFO(HCI_TAPI_STR"CONNECTED to USB CDC Stream");
        hciTapPrivateData.state = HCI_TAP_CONNECTED_TO_USB;
    }
    return retVal;
}

/* PUBLIC FUNCTIONS **********************************************************/
bool hciTapStream_ConnectStream(Source src, Sink sink)
{
    Transform t = StreamConnect(src, sink);
    if(NULL == t)
    {
        DEBUG_LOG_WARN(HCI_TAPW_STR"FAIL to CONNECT to Source:%x Sink:%x",
                       src, sink);
        return FALSE;
    }
    else
    {
        hciTapPrivateData.src = src;
        hciTapPrivateData.sink = sink;
        TransformConfigure(t, VM_TRANSFORM_COPY_FRAGMENT_DATA, 1);
        return TRUE;
    }
}

void HciTapStream_Disconnect(void)
{
    if (hciTapPrivateData.src == NULL)
    {
        DEBUG_LOG_INFO(HCI_TAPI_STR"Already Disconnected");
        return;
    }
    switch(hciTapPrivateData.state)
    {
        case HCI_TAP_CONNECTED_TO_USB:
            StreamDisconnect(hciTapPrivateData.src, hciTapPrivateData.sink);
            (void) SourceClose(hciTapPrivateData.src);
            UsbApplication_Close();
            DEBUG_LOG_INFO(HCI_TAPI_STR"USB CDC and HCI-TAP streams are DISCONNECTED");
        break;
        case HCI_TAP_CONNECTED_TO_UART:
            StreamDisconnect(hciTapPrivateData.src, hciTapPrivateData.sink);
            (void) SourceClose(hciTapPrivateData.src);
            (void) SinkClose(hciTapPrivateData.sink);
            DEBUG_LOG_INFO(HCI_TAPI_STR"UART and HCI-TAP streams are DISCONNECTED");
            break;
        case HCI_TAP_DISCONNECTED: /*falthrough */
        default:
            DEBUG_LOG_INFO(HCI_TAPI_STR"Only source existed. Freeing it!");
            (void) SourceClose(hciTapPrivateData.src);
            break;
    }
    hciTapPrivateData.sink = NULL;
    hciTapPrivateData.src = NULL;
    hciTapPrivateData.state = HCI_TAP_DISCONNECTED;
}

bool HciTapStream_ConnectToCDCDevice(void)
{
    if (HCI_TAP_DISCONNECTED != hciTapPrivateData.state)
    {
        DEBUG_LOG_WARN(HCI_TAPW_STR"ALREADY CONNECTED - call testHciTapStream_Disconnect first");
        return FALSE;
    }
    UsbApplication_Open(&usb_app_cdc); /* see appTestUsbCdcInit*/
    return hciTapStream_ConnectToCDCDeviceComplete();
}

#endif /*ENABLE_HCI_TAP_STREAM*/
/*! @} !*/
